Android 13 新的换行策略和针对日文的优化
前言
Android 13 向 TextView
控件引入了新的换行策略,同时针对日文提供了换行优化。系统将依据开发者指定的换行策略、日文短语换行策略进行文本换行。这将促使文本内容不再杂乱无章、更加具有层次、便于阅读。
下面我们从 API、实战、适配办法等多个角度来快速学习一下这个新特性。
换行策略 lineBreakStyle
Indicates the line break strategies can be used when calculating the text wrapping.
Constant | Value | Description |
---|---|---|
none | 0 | No line break style specific. |
loose | 1 | Use the least restrictive rule for line-breaking. |
normal | 2 | Indicate breaking text with the most comment set of line-breaking rules. |
strict | 3 | ndicates breaking text with the most strictest line-breaking rules. |
事实上来自于 CSS
的 line-break
属性,主要是针对 CJK
语言,也就是中日韩 3 种语言提供的换行规则。
Android 提供的属性和 CSS 的略有差异,但 loose
、normal
和 strict
这三个属性进行了保留,后面将通过 DEMO 进行属性表现上的差异说明。
短语换行策略 lineBreakWordStyle
Specify the phrase-based line break can be used when calculating the text wrapping.
Constant | Value | Description |
---|---|---|
none | 0 | No line break word style specific. |
phrase | 1 | Specify the phrase based breaking. |
默认不生效,设置为 phrase
则生效。
动态设置
除了上述属性以外,TextView 理所应当地提供了 setLineBreakConfig()
来动态更新换行策略。
public void setLineBreakConfig (LineBreakConfig lineBreakConfig)
Parameters | |
---|---|
lineBreakConfig | LineBreakConfig : the line break config for text wrapping. This value cannot be null . |
LineBreakConfig
Android 13 新引入的承载换行策略的配置类,提供了上述属性相对应的常量以及返回策略所必要的 get 方法。
Constants | |
---|---|
int | LINE_BREAK_STYLE_LOOSE Use the least restrictive rule for line-breaking. |
int | LINE_BREAK_STYLE_NONE No line break style specified. |
int | LINE_BREAK_STYLE_NORMAL Indicate breaking text with the most comment set of line-breaking rules. |
int | LINE_BREAK_STYLE_STRICT Indicates breaking text with the most strictest line-breaking rules. |
int | LINE_BREAK_WORD_STYLE_NONE No line break word style specified. |
int | LINE_BREAK_WORD_STYLE_PHRASE Indicates the line breaking is based on the phrased. |
public int getLineBreakWordStyle ()
public int getLineBreakStyle ()
实战
我们在中文和日语两种语言环境下提供一些测试文本,探究在不同换行策略下文本的实际表现。
换行策略的效果
换行策略的表现跟 CJK 语言里一些特定符号有关系,普通的文本表现上区别不是很明显。所以我们预设特别的一段文本在不同的显示宽度下的表现,来简要展现下不同规则下的差异。
测试文本:这里有个弯弯符号〜加“引号”然后最后有个问号?后面是普普通通一句话。
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
LineBreakConfig().run {
lineBreakStyle = LINE_BREAK_STYLE_NONE
lineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE
breakTestTextViewCSS.lineBreakConfig = this
breakTestTextViewCSS_2.lineBreakConfig = this
}
}
fun onButtonClick(view: View) {
when (view.id) {
R.id.break_btn -> breakTestTextViewCSS.lineBreakConfig.apply {
lineBreakStyle =
when (breakTestTextViewCSS.lineBreakConfig.lineBreakStyle) {
LINE_BREAK_STYLE_NONE -> LINE_BREAK_STYLE_LOOSE
LINE_BREAK_STYLE_LOOSE -> LINE_BREAK_STYLE_NORMAL
LINE_BREAK_STYLE_NORMAL -> LINE_BREAK_STYLE_STRICT
LINE_BREAK_STYLE_STRICT -> LINE_BREAK_STYLE_NONE
else -> LINE_BREAK_STYLE_NONE
}
breakTestTextViewCSS.lineBreakConfig = this
breakTestTextViewCSS_2.lineBreakConfig = this
}
}
}
}
NONE | LOOSE |
---|---|
NORMAL | STRICT |
---|---|
可以看到
none 和 strict 策略下,符号 〜
的前方必须有文字,不能单独作为行首,而 loose 和 normal 策略则无此限制另外按照 css 的说明,只有在 strict 策略下,符号 〜
才允许作为行尾进行换行。但在 Android 13 上的测试发现,无论哪种策略都允许符号〜
作为行尾换行,可能跟宽度配置有些关系loose 策略下,符号 ?
允许在行首单独出现,而其他模式不允许,前面必须要有其他文字才可换行
其他更详细的换行差异可以参考 w3c
的 css 换行说明,并进行实际的尝试。
短语换行策略效果
短语换行策略指的是日文情况下句尾遇到短语、助词如何换行,是固定换行还是短语整体另起一行。
测试文本:常に最新、最高のモバイル。Androidを開発した同じチームから。
起初觉得只要展示的是日文都会应用该策略,便没有注意 App 当前语言是中文,以外发现画面中的日文文本没有按照预期进行换行。
class MainActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
LineBreakConfig().run {
lineBreakStyle = LINE_BREAK_STYLE_NONE
lineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE
breakTestTextView.lineBreakConfig = this
}
}
fun onButtonClick(view: View) {
when (view.id) {
R.id.phrase_break_btn -> breakTestTextView.lineBreakConfig.apply {
lineBreakWordStyle =
if (breakTestTextView.lineBreakConfig.lineBreakWordStyle == LINE_BREAK_WORD_STYLE_PHRASE)
LINE_BREAK_WORD_STYLE_NONE
else LINE_BREAK_WORD_STYLE_PHRASE
breakTestTextView.lineBreakConfig = this
}
}
}
}
需要当前语言是日语
当 App 语言切换为日语场景后,短语换行策略才会生效。
后来想想也是合理的,非日语的场景下用户能读懂日语的概率很低,在意换行的可能性更加小。系统没有必要耗费精力去判断文字是否是日文和进行换行。
而当 App 语言是日语的话,用户极高概率能读懂并且在乎短语换行的合理和连贯性,所以只在日语情况下生效则显得非常合理。
性能测试
可能有开发者会担心开启了短语换行是否造成性能的负担。通过覆写 TextView 并在 onMeasure()
里加入耗时统计,测定了展示 10000 个杂乱的日文文本下,短语换行策略开启与否的时间表现。
设备版本是:Pixel 4 XL 13 Beta 1
workBreakStyle | phrase(ms) | none(ms) |
---|---|---|
22 | 19 | |
2 | 22 | 20 |
3 | 23 | 20 |
4 | 28 | 21 |
5 | 22 | 20 |
6 | 22 | 25 |
7 | 28 | 19 |
8 | 22 | 20 |
9 | 29 | 25 |
10 | 22 | 25 |
可以看到即便是长度达到 10000 的超长文本,开启了短语换行策略的性能表现依旧没有什么明显劣化。在实际开发当中,显示长度达到 10000 的 TextView 文本的情况实属罕见。
我们可以断定短语换行策略对于文本显示的性能影响可以忽略不计。
另外,需要说明的是 TargetSDKVersion
不用升级到 33,所有的换行特性均可生效。
原理
目前只公开了 preview-1
的代码,搜索了一下没有发现 LineBreakConfig 相关的实现,后续等 Beta
版代码公开之后再作研究。
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android-t-preview-1/
适配
思考下 App 是否需要开启新的换行策略 如果 App 支持日语的话,建议开启短语换行策略,优化日文的阅读体验 确定开启上述新策略的话,需要注意如下两点影响:
画面布局是否发生错乱、切掉 与已有的日文手动换行 \n
是否会发生冲突
总结
本新特性非常简单直白,我们可以使用换行策略去指定和 css 一致的换行规则,也可以针对日语指定换行友好的短语策略。
和 View 的一般用法无差,均有属性配置和动态更新两种方案。
另外,留意如下几点:
该新特性不要求升级 TargetSDKVersion
指定换行策略的话需要留意布局是否发生错乱、切掉的问题 指定短语换行策略的话需要检查是否会和已有的手动换行发生冲突 当前语言是日语环境下,短语换行策略才可以生效 短语换行策略对于性能的影响可以忽略不计
参考资料
https://developer.android.google.cn/about/versions/13/features#language-support https://developer.android.google.cn/reference/android/widget/TextView https://developer.android.google.cn/reference/android/graphics/text/LineBreakConfig https://www.w3.org/TR/css-text-3/#line-break-property https://www.zhangxinxu.com/wordpress/2021/02/css-line-break/